# -*- coding: utf-8 -*-

import wx
import wxMusicTagger

import os
import Image
from modules import MusicFile
from threading import *

class MainFrame( wxMusicTagger.MainFrame ):
    
    # standard image dimensions
    std_width   = 300
    std_height  = 300
        
    album_files = {}
    
    _worker = None
    _metadata = []
        
    def __init__( self, parent ):
        wxMusicTagger.MainFrame.__init__( self, parent )
        
        # setup columns
        self.list_files.InsertColumn(0, "Titel", width=wx.LIST_AUTOSIZE);
        self.list_files.InsertColumn(1, "Interpret", width=wx.LIST_AUTOSIZE);
        self.list_files.InsertColumn(2, "Album", width=wx.LIST_AUTOSIZE);
        
        EVT_RESULT(self,self.on_picture_set_finished)
        
        self.SetMinSize(self.GetSize())
    
    def on_picture_set_finished(self, event):
        
        ###
        ### TODO: handle returned exit code
        ###
        
        self._worker = None
        self.on_dir_changed(None)
        
    def on_song_select(self, event):
        
        ## reset album picture
        self.pic_picture.SetBitmap(wx.EmptyBitmap(width=0, height=0))
        
        ## disable apply button
        self.btn_apply_pic.Disable()
        selected = self.list_files.GetFirstSelected()
        
        metadata = self._metadata[selected]
        
        if metadata:
            tmp = metadata.getPicture()
            if tmp:
                img = wx.EmptyImage(tmp.size[0], tmp.size[1])
                img.SetData(tmp.convert("RGB").tostring())
                img = scale_image(img, self.std_width, self.std_height)
                self.pic_picture.SetBitmap(img)
                self.file_picture.SetPath("[in der Datei]")
                self.btn_extract.Enable()
            else:
                ## there's no picture
                self.file_picture.SetPath("...")
                self.btn_extract.Disable()
         
    def on_dir_changed(self, event):
        
        ## clear list
        self.list_files.DeleteAllItems()
        ## reset album picture
        self.pic_picture.SetBitmap(wx.EmptyBitmap(width=0, height=0))
        
        ## reset cached metadata
        self._metadata = []
        
        if os.path.isdir(self.dir_album.GetPath()):
            path = self.dir_album.GetPath()
            
            ## read content of chosen directory
            dir_contents = os.listdir(path)
            self.gauge_progressbar.SetValue(0)
            self.gauge_progressbar.SetRange(len(dir_contents))
            for file in dir_contents:
                fullpath = os.path.join(path, file)
                increase_progress(self.gauge_progressbar)
                wx.Yield()
                if not file.startswith("."):
                    item_count = self.list_files.GetItemCount()
                    
                    ## get metadata
                    metadata = MusicFile(fullpath)
                    
                    if metadata:
                        self._metadata.append(metadata)
                        self.list_files.InsertStringItem(item_count, metadata['title'])
                        self.list_files.SetStringItem(item_count, 1, metadata['artist'])
                        self.list_files.SetStringItem(item_count, 2, metadata['album'])
                        
                        self.album_files[item_count] = fullpath
                        if metadata.getPicture():
                            self.list_files.SetItemBackgroundColour(item_count, wx.Colour(0,255,0,55))

            if dir_contents:
                column_count = self.list_files.GetColumnCount()
                for col in range(column_count):
                    self.list_files.SetColumnWidth(col, width=wx.LIST_AUTOSIZE)
                self.list_files.Select(0)
    
    def on_mouse_over_list(self, event):
        toSel, flag = self.list_files.HitTest( event.GetPosition() )
        
        if toSel != -1:
            self.list_files.SetToolTip(wx.ToolTip(os.path.basename(self.album_files[toSel])))
            self.statusbar.SetStatusText(self.album_files[toSel])
        else:
            self.statusbar.SetStatusText("")
        
    
    def on_pic_chosen(self, event):
        if os.path.isfile(self.file_picture.GetPath()):
            
            path = self.file_picture.GetPath()
            image = wx.Bitmap(path)
            
            thumb = scale_image(image, self.std_width, self.std_height)
            self.pic_picture.SetBitmap(thumb)
            
            try:
                img = Image.open(path)
            except IOError,e:
                if e.message == "cannot identify image file":
                    # loaded file is not in a supported format
                    self.btn_apply_pic.Disable()
                    self.btn_extract.Disable()
                    self.file_picture.SetPath(u"[Format ungültig]")
                    return
            
            self.btn_extract.Disable()
            self.btn_apply_pic.Enable()
    
    def on_picture_apply(self, event):
        if not self._worker:
            self.gauge_progressbar.SetValue(0)
            self._worker = PictureSetThread(self,
                                            list(self.album_files.values()),
                                            self.file_picture.GetPath(),
                                            self.std_width,
                                            self.std_height,
                                            self.gauge_progressbar)




class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data




# Thread class that sets pictures
class PictureSetThread(Thread):
    
    _progressbar = None
    _files = None
    _path_to_picture = None
    _width = None
    _height = None
    _notify_window = None
    _want_abort = None
    
    def __init__(self, notify_window, files, path_to_picture, width, height, progressbar=None):
        Thread.__init__(self)
        self._notify_window = notify_window
        self._want_abort = 0
        self._files = files
        self._path_to_picture = path_to_picture
        self._width = width
        self._height = height
        if progressbar:
            self._progressbar = progressbar
        self.start()

    def run(self):
        if self._progressbar:
            self._progressbar.SetRange(len(self._files))
        
        self.setPicture(self._files,
                        self._path_to_picture,
                        self._width,
                        self._height)
        wx.PostEvent(self._notify_window, ResultEvent(0))

    def abort(self):
        """abort worker thread."""
        # Method for use by main thread to signal an abort
        self._want_abort = 1
    
    
    def setPicture(self, file_list, pic_path, width, height):
    
        picture = Image.open(pic_path)
        picture = picture.resize((width, height))
    
        for file in file_list:
            #print u"working in %s" % (file)
            if self._want_abort:
                wx.PostEvent(self._notify_window, ResultEvent(1))
            if not os.path.isfile(file):
                continue
            
            metadata = MusicFile(file)
            metadata.setPicture(picture)
            increase_progress()

## Useful functions =)

def increase_progress(progressbar = None):
    if progressbar:
        i = progressbar.GetValue()
        progressbar.SetValue(i+1)

def scale_image(image, width, height):
    
    if isinstance(image, wx._gdi.Bitmap):
        image = wx.ImageFromBitmap(image)
    image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
    result = wx.BitmapFromImage(image)
    return result

EVT_RESULT_ID = wx.NewId()
def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class CoverEmbed(wx.App):
    
    def OnInit(self):
        frame = MainFrame(None)
        frame.Show()
        frame.SetTitle("CoverEmbed")
        self.SetTopWindow(frame)
        wx.Log.EnableLogging(False) 
        return True

if __name__ == "__main__":
    app = CoverEmbed(0)
    app.MainLoop()